﻿namespace Sai.Test
{
	using System.IO;
	using System.Xml.Serialization;
	using Sai.Core;
	using Sai.Test.TestDataBuilders;
	using Xunit;
    using Sai.Test.XUnit;
    using Sai.Core.Reporting;

	public class ProductReleaseFacts
	{
		public class OnSerialization
		{
			
			[Fact, InMemoryTest]
			public void Creates_MultiLine_Format()
			{
				var release = new ProductRelease();
				release.VersionName = "Version 1";

				release.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("MyAssembly")
									.Build());

                string output = ObjectFlattener<ProductRelease>.Flatten(release);

				Assert.Contains("<Release ", output);
				Assert.Contains(" Version=\"Version 1\"", output);
				Assert.Contains("<Assemblies>", output);
				Assert.Contains("<Assembly ", output);
				Assert.Contains(" Name=\"MyAssembly\" />", output);
				Assert.Contains("</Assemblies>", output);
			}
		}

		public class TheCommonAssembliesMethod
		{
			
			[Fact, InMemoryTest]
			public void With_Same_Names_Different_Folders_Returns_All_In_Common()
			{
				var oldRelease = new ProductRelease();

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("MyAssembly")
									.InFolder("C:\\Version1")
									.Build());

				var newRelease = new ProductRelease();

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("MyAssembly")
									.InFolder("C:\\Version2")
									.Build());

				var inCommon = newRelease.CommonAssemblies(oldRelease);

				Assert.Equal(1, inCommon.Count);
			}

			
			[Fact, InMemoryTest]
			public void With_Different_Names_Different_Folders_Returns_Nothing_In_Common()
			{
				var oldRelease = new ProductRelease();

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("MyAssembly1")
									.InFolder("C:\\Version1")
									.Build());

				var newRelease = new ProductRelease();

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("MyAssembly2")
									.InFolder("C:\\Version2")
									.Build());

				Assert.Empty(newRelease.CommonAssemblies(oldRelease));
			}

			
			[Fact, InMemoryTest]
			public void Partial_Content_Returns_Parts_In_Common()
			{
				var oldRelease = new ProductRelease();

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly1")
									.InFolder("C:\\Version1")
									.Build());

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version1")
									.Build());

				var newRelease = new ProductRelease();

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version2")
									.Build());

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly3")
									.InFolder("C:\\Version2")
									.Build());

				var inCommon = newRelease.CommonAssemblies(oldRelease);

				Assert.Equal(1, inCommon.Count);
				Assert.Equal("Assembly2", inCommon[0].Name);
			}
		}

		public class TheAddedAssembliesMethod
		{
			
			[Fact, InMemoryTest]
			public void Partial_Content_Returns_Unique_Parts()
			{
				var oldRelease = new ProductRelease();

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly1")
									.InFolder("C:\\Version1")
									.Build());

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version1")
									.Build());

				var newRelease = new ProductRelease();

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version2")
									.Build());

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly3")
									.InFolder("C:\\Version2")
									.Build());

				var onlyInNew = newRelease.AddedAssemblies(oldRelease);

				Assert.Equal(1, onlyInNew.Count);
				Assert.Equal("Assembly3", onlyInNew[0].Name);
			}
		}

		public class TheRemovedAssembliesMethod
		{
			
			[Fact, InMemoryTest]
			public void Partial_Content_Returns_Unique_Parts()
			{
				var oldRelease = new ProductRelease();

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly1")
									.InFolder("C:\\Version1")
									.Build());

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version1")
									.Build());

				var newRelease = new ProductRelease();

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version2")
									.Build());

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly3")
									.InFolder("C:\\Version2")
									.Build());

				var onlyInOld = newRelease.RemovedAssemblies(oldRelease);

				Assert.Equal(1, onlyInOld.Count);
				Assert.Equal("Assembly1", onlyInOld[0].Name);
			}
		}

		public class TheCompareToMethod
		{
			
			[Fact, InMemoryTest]
			public void Partial_Content_Returns_List_With_Added_Removed_Parts()
			{
				var oldRelease = new ProductRelease();

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly1")
									.InFolder("C:\\Version1")
									.Build());

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version1")
									.Build());

				oldRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly3")
									.InFolder("C:\\Version1")
									.Build());

				var newRelease = new ProductRelease();

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly2")
									.InFolder("C:\\Version2")
									.WithChecksum("thishaschanged")
									.Build());

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly3")
									.InFolder("C:\\Version2")
									.Build());

				newRelease.Add(ProductAssemblyBuilder.ProductAssembly()
									.Named("Assembly4")
									.InFolder("C:\\Version2")
									.Build());

				var comparisonList = newRelease.CompareTo(oldRelease);

				Assert.Equal(4, comparisonList.Count);

				int addedCount = 0;
				int removedCount = 0;
				int noChangeCount = 0;
				int indeterminateCount = 0;

				foreach (var item in comparisonList)
				{
					if (item.Result == AssemblyComparisonResult.Added)
					{
						Assert.Null(item.Old);
						Assert.NotNull(item.New);
						++addedCount;
					}
					else if (item.Result == AssemblyComparisonResult.Removed)
					{
						Assert.NotNull(item.Old);
						Assert.Null(item.New);
						++removedCount;
					}
					else if (item.Result == AssemblyComparisonResult.NoChange)
					{
						Assert.NotNull(item.Old);
						Assert.NotNull(item.New);
						++noChangeCount;
					}
					else if (item.Result == AssemblyComparisonResult.Indeterminate)
					{
						Assert.NotNull(item.Old);
						Assert.NotNull(item.New);
						++indeterminateCount;
					}
				}

				Assert.Equal(1, addedCount);
				Assert.Equal(1, removedCount);
				Assert.Equal(1, noChangeCount);
				Assert.Equal(1, indeterminateCount);
			}
		}
	}
}
